package com.dashan.backend;

import java.security.AccessControlException;
import java.util.Date;

import javax.jdo.JDOObjectNotFoundException;

import com.dashan.backend.datastore.DsSession;
import com.dashan.backend.datastore.DsUser;
import com.dashan.backend.datastore.SessionDao;
import com.dashan.backend.datastore.UserDao;
import com.dashan.backend.datastore.DsSession.Status;
import com.dashan.backend.util.EncriptionHelper;

public class AuthenticationManager {
    
    public static final int SALT_LENGTH = 10;
    
    /**
     * Get a new salt for a new user session.
     * 
     * @param userName
     * @return a randomly generated salt string
     */
    public static String getSalt(String userName) {
        UserDao dao = new UserDao();
        SessionDao sessionDao = new SessionDao();
        try {
            if (!dao.isUserExist(userName)) {
                throw new JDOObjectNotFoundException("User not found: " + userName);
            }
            DsSession dsSession = sessionDao.getLastSession(userName, Status.ACTIVE);
            if (dsSession != null) {
                dsSession.setStatus(Status.EXPIRED);
                sessionDao.updateSession(dsSession);
            }
            
            String salt = EncriptionHelper.randomString(SALT_LENGTH);
            DsSession newSession = new DsSession(userName, salt, new Date());
            sessionDao.createSession(newSession);
            return salt;
        } finally {
            dao.commit();
            sessionDao.commit();
        }
    }
    
    /**
     * Try to authenticate a user session. 
     * 
     * @return the sessionid
     * @throws SecurityException
     */
    public static long getSessionId(String userName, String saltedPwdSha) throws SecurityException {
        UserDao dao = new UserDao();
        SessionDao sessionDao = new SessionDao();
        try {
            DsUser user = dao.getUser(userName);
            DsSession dsSession = sessionDao.getLastSession(userName, Status.INITIAL);
            
            if (dsSession == null) {
                throw new AccessControlException(
                "No session waiting for authenticate. Please request a salt again.");
            }
            
            String serverString = EncriptionHelper.saltPwd(user.getPwdSha(), dsSession.getSalt());
            String clearServerString = user.getPwdSha() + dsSession.getSalt();
            if (serverString.compareTo(saltedPwdSha) == 0
                    || clearServerString.compareTo(saltedPwdSha) == 0) {
                dsSession.setStatus(Status.ACTIVE);
            } else {
                dsSession.setStatus(Status.EXPIRED);
                throw new AccessControlException("Authenticate failed! Please request a salt again.");
            }
            return dsSession.getId();
        } finally {
            dao.commit();
            sessionDao.commit();
        }
    }
    
    /**
     * Get if the session id can be authenticated.
     * 
     * @param userName
     * @param sessionId
     * @return true for active session
     */
    public static boolean getAuthentication(String userName, long sessionId) {
        SessionDao sessionDao = new SessionDao();
        try {
            DsSession dsSession = sessionDao.getLastSession(userName, Status.ACTIVE);
            if (dsSession == null) {
                return false;
            }
            return dsSession.getId() == sessionId;
        } finally {
            sessionDao.commit();
        }
    }
}
